import requests
from django.conf import settings  # Django统一调用配置文件的导入方式
from urllib import parse
from urllib.request import urlopen
import logging
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import BadData
import json

from .exceptions import OAuthQQAPIError, OAuthWBAPIError
from . import constants

logger = logging.getLogger('django')


class OAuthQQ(object):
    """
    QQ登录辅助工具类
    """

    def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):
        self.client_id = client_id or settings.QQ_CLIENT_ID
        self.client_secret = client_secret or settings.QQ_CLIENT_SECRET
        self.redirect_uri = redirect_uri or settings.QQ_REDIRECT_URI  # 回调地址
        self.state = state or settings.QQ_STATE  # 用于保存登录成功后的跳转页面路径

    def get_qq_login_url(self):
        """
        返回QQ登录网址
        """
        url = 'https://graph.qq.com/oauth2.0/authorize?'

        params = {
            'response_type': 'code',
            'client_id': self.client_id,
            'redirect_uri': self.redirect_uri,
            'state': self.state
        }

        url += parse.urlencode(params)  # 将params字典转换为url路径中的查询字符串

        return url

    def get_access_token(self, code):
        url = 'https://graph.qq.com/oauth2.0/token?'

        params = {
            'grant_type': 'authorization_code',
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': code,
            'redirect_uri': self.redirect_uri
        }

        url += parse.urlencode(params)

        try:
            # 根据网址发送请求
            # access_token = FE04 ** ** CCE2 & expires_in = 7776000 & refresh_token = 88E4 **  ** BE14
            resp = urlopen(url)

            resp_data = resp.read()  # 读取响应体数据,bytes
            resp_data = resp_data.decode()   # str

            resp_dict = parse.parse_qs(resp_data)  # 将resp_data查询字符串格式数据转换为python的字典
        except Exception:
            logger.error('获取access_token失败')
            raise OAuthQQAPIError

        access_token = resp_dict['access_token']

        return access_token[0]

    def get_openid(self, access_token):
        url = 'https://graph.qq.com/oauth2.0/me?access_token=' + access_token

        try:
            # 根据网址发送请求
            # callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )\n;
            resp = urlopen(url)

            resp_data = resp.read()  # 读取响应体数据,bytes
            resp_data = resp_data.decode()   # str

        except Exception:
            logger.error('获取openid失败')
            raise OAuthQQAPIError

        data = json.loads(resp_data[10:-4])
        openid = data.get('openid', None)

        return openid

    @staticmethod
    def generate_access_token(openid):

        # serializer = Serializer(秘钥, 有效期秒)
        serializer = Serializer(settings.SECRET_KEY, constants.BIND_USER_ACCESS_TOKEN_EXPIRES)
        # serializer.dumps(数据), 返回bytes类型
        access_token = serializer.dumps({'openid': openid})
        return access_token.decode()

    @staticmethod
    def check_access_token(access_token):
        # 检验token
        # 验证失败，会抛出itsdangerous.BadData异常
        serializer = Serializer(settings.SECRET_KEY, constants.BIND_USER_ACCESS_TOKEN_EXPIRES)
        try:
            data = serializer.loads(access_token)
        except BadData:
            return None
        else:
            return data.get('openid')


class OAuthWB(object):
    """
    微博登录辅助工具类
    """
    # 创建对象属性传参
    def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):
        self.client_id = client_id or settings.WB_CLIENT_ID
        self.client_secret = client_secret or settings.WB_CLIENT_SECRET
        self.redirect_uri = redirect_uri or settings.WB_REDIRECT_URI  # 回调地址
        # self.state = state if state else settings.WB_STATE
        self.state = state or settings.WB_STATE  # 用于保存登录成功后的跳转页面路径

    def get_wb_login_url(self):
        """
        返回微博登录网址
        """
        # https://api.weibo.com /oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
        url = 'https://api.weibo.com/oauth2/authorize?'

        params = {
            'response_type': 'code',
            'client_id': self.client_id,
            'redirect_uri': self.redirect_uri,
            'state': self.state    # 用于保存登录成功后的跳转页面路径
        }

        url += parse.urlencode(params)  # 将params字典转换为url路径中的查询字符串
        # 可以将{'a':1, 'b':2}转换为a=1&b=2

        return url

    def get_access_token(self, code):
        """
        :param code:微博提供的code
        :return: access_token
        """
        # https://api.weibo.com/oauth2/access_token?client_id = YOUR_CLIENT_ID & client_secret = YOUR_CLIENT_SECRET & grant_type = authorization_code & redirect_uri = YOUR_REGISTERED_REDIRECT_URI & code = CODE

        params = {
            'grant_type': 'authorization_code',
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': code,
            'redirect_uri': self.redirect_uri
        }

        url = 'https://api.weibo.com/oauth2/access_token?' + parse.urlencode(params)

        reponse = requests.post(url=url,data=params)
        access_token = reponse.text
        if not access_token:
            logger.error('code=%s' % code)
            raise OAuthWBAPIError
        return json.loads(access_token)






